﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Tools.Ribbon;
using Microsoft.Office.Tools;
using System.Windows.Forms;
using System.Net;
using DosciWordPlugin.Common;
using DosciWordPlugin.Models;
using DosciWordPlugin.Controls;
using Microsoft.Office.Interop.Word;
using System.IO;

namespace DosciWordPlugin
{
    public partial class DosciMenu
    {
        List<ReferencePanelModel> _refPanelModelList = new List<ReferencePanelModel>();
        Login _login = new Login();
        InsertCitation _insertCitation = new InsertCitation();
        InsertOther _insertOther = new InsertOther();
        WordTemplates _wordTemplate = new WordTemplates();
        SetCitationStyle _setCitationStyle = new SetCitationStyle();

        #region 事件响应
        private void DosciMenu_Load(object sender, RibbonUIEventArgs e)
        {
            try
            {
                Globals.ThisAddIn.Application.DocumentChange += new ApplicationEvents4_DocumentChangeEventHandler(Application_DocumentChange);

                _insertOther.InsertOtherTextEvent += this.InsertOtherText;
                _insertCitation.AddToPanelEvent += this.AddToPanel;

                citationStyle.SelectionChanged += new RibbonControlEventHandler(citationStyle_SelectionChanged);

                UpdateLoginStatus();
                
                HttpUtil.TokenExpiredEvent += () => {
                    UpdateLoginStatus();
                    _refPanelModelList.ForEach(r => { r.RefPanel.ClearRefrence(); });
                };
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        void citationStyle_SelectionChanged(object sender, RibbonControlEventArgs e)
        {
            try
            {
                ApplyCitationStyle();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        void Application_DocumentChange()
        {
            Window activeWindow;
            try
            {
                activeWindow = Globals.ThisAddIn.Application.ActiveWindow;
            }
            catch (Exception)
            {
                return;
            }

            try
            {
                //有可能需要释放已关闭文档的reference panel，待观察
                List<Window> existWindows = new List<Window>();
                foreach (Window window in Globals.ThisAddIn.Application.Windows)
                {
                    existWindows.Add(window);
                }
                var needReleaseList = _refPanelModelList.FindAll(m => !existWindows.Exists(w=>w==m.Window));
                needReleaseList.ForEach(r => { Globals.ThisAddIn.CustomTaskPanes.Remove(r.TaskPane); _refPanelModelList.Remove(r);});
                
                if (GetRefPanelModel(activeWindow) == null)
                {
                    var refPanel = new ReferencePanel();
                    refPanel.InsertCitationEvent += InsertCitation;
                    refPanel.SetCitationStyleEvent += PanelSetCitationStyle;
                    refPanel.SearchCitationEvent += PanelSearchCitation;
                    refPanel.RefreshCitationStatusEvent += PanelRereshCitationStatus;
                    ReferencePanelModel refPanelModel = new ReferencePanelModel
                    {
                        Window = activeWindow,
                        RefPanel = refPanel,
                        TaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(refPanel, "引用面板"),
                    };
                    refPanelModel.TaskPane.Visible = ckRefPanel.Checked;
                    // 反过来，手动关闭panel时，ckRefPanel也需要响应
                    refPanelModel.TaskPane.VisibleChanged += (o, e) =>
                    {
                        var activePanelModel = GetRefPanelModel();
                        if (activePanelModel != null &&
                            ckRefPanel.Checked != activePanelModel.TaskPane.Visible)
                            ckRefPanel.Checked = activePanelModel.TaskPane.Visible;
                    };
                    _refPanelModelList.Add(refPanelModel);
                    
                    // 请求面板数据
                    if (CacheManager.UserInfo != null)
                        QueryUserReferencePanelData();
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        private void btnInsertCitation_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                if (!CheckLogin()) return;
                
                _insertCitation.EnableInsert = true;
                _insertCitation.ShowDialog();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        private void btnInsertOtherText_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                if (!CheckLogin()) return;

                _insertOther.ShowDialog();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        private void btnGotoDosci_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                string token = "";
                if (CacheManager.UserInfo != null) token = "?token="+CacheManager.UserInfo.Token;
                System.Diagnostics.Process.Start(Constant.HOST + token);
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        private void ckRefPanel_Click(object sender, RibbonControlEventArgs e)
        {
            var refPanelModel = GetRefPanelModel();
            if (refPanelModel != null)
                refPanelModel.TaskPane.Visible = ckRefPanel.Checked;
        }

        private void btnTemplates_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                if (!CheckLogin()) return;
                
                if (_wordTemplate.ShowDialog() != DialogResult.OK) return;

                TemplateModel selectedTemplate = _wordTemplate.SelectedTemplate;
                if (selectedTemplate==null)
                {
                    WinApp.MsgBoxError("请选择模板！");
                    return;
                }

                // 查找本地是否存在对应模板
                if (!File.Exists(selectedTemplate.LocalFilePath))
                {
                    WinApp.MsgBoxError("模板不存在！");
                    return;
                }

              
                // 应用模板
                var doc = Globals.ThisAddIn.Application.ActiveDocument;
                string docPath = doc.FullName;
                string templatePath = selectedTemplate.LocalFilePath;

                doc.Close();
                string targetPath = File.Exists(docPath) ? docPath.Replace(".docx",".doc") : templatePath.Replace(".dot", ".doc");
                File.Copy(templatePath, targetPath, true);
                Globals.ThisAddIn.Application.Documents.Open(targetPath);
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        private void btnRefreshCitation_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                if (!CheckLogin()) return;

                ApplyCitationStyle();
                RefreshCitationPanelStatus();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        /// <summary>
        /// 检测原创性
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDetectOriginal_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {

            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        /// <summary>
        /// 上传当前文档到远程服务器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConvertToDosci_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        private void btnLoginLogout_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                if (CacheManager.UserInfo == null)
                {
                    CheckLogin();
                }
                else
                {
                    if (WinApp.MsgBoxOkCancel("确定退出dosci登录吗?") == DialogResult.OK)
                    {
                        Dictionary<string, string> dicParam = new Dictionary<string, string>();

                        HttpUtil.Post<string>(Constant.API_退出, dicParam);
                        UpdateLoginStatus();
                        var refPanelModel = GetRefPanelModel();
                        if (refPanelModel != null) refPanelModel.RefPanel.ClearRefrence();
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        #endregion

        #region 逻辑函数
        private ReferencePanelModel GetRefPanelModel(Window window = null)
        {
            try
            {
                window = window == null ? Globals.ThisAddIn.Application.ActiveWindow : window;
                ReferencePanelModel findedRelPanelModel = _refPanelModelList.Find(m => m.Window == window);
                return findedRelPanelModel;
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                return null;
            }
            
        }

        private bool CheckLogin()
        {
            try
            {
                if (CacheManager.UserInfo != null) return true;

                if (_login.ShowDialog() == DialogResult.OK)
                {
                    UpdateLoginStatus();
                    QueryUserReferencePanelData();
                    return true;
                }
            }
            catch (Exception ex)
            {
                WinApp.MsgBoxError(ex.Message);
                LogHelper.Error(ex);
            }

            return false;
        }

        private void UpdateLoginStatus()
        {
            if (CacheManager.UserInfo != null)
            {
                lbUsername.Label = CacheManager.UserInfo.RealName;
                btnLoginLogout.Label = "退出";
            }
            else
            {
                lbUsername.Label = "请登录";
                btnLoginLogout.Label = "登录";
            }
        }

        private bool InsertOtherText(string content)
        {
            try
            {
                var doc = Globals.ThisAddIn.Application.ActiveDocument;
                var endNotes = doc.Endnotes;

                endNotes.Add(Globals.ThisAddIn.Application.Selection.Range, Type.Missing, content);
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }

            return false;
        }

        private bool InsertCitation(List<ReferenceModel> modelList)
        {
            try
            {
                if (citationStyle.SelectedItem == null)
                {
                    WinApp.MsgBoxError("请设置要插入的格式");
                    return false;
                }

                var doc = Globals.ThisAddIn.Application.ActiveDocument;
                var endNotes = doc.Endnotes;

                string style = citationStyle.SelectedItem.Label;
                if (string.IsNullOrEmpty(style))
                {
                    WinApp.MsgBoxError("样式不能为空");
                    return false;
                }

                Dictionary<string, string> dicParam = new Dictionary<string, string>();
                dicParam.Add("id", string.Join(",", modelList.Select(m => m.ID).Distinct().ToArray()));
                dicParam.Add("style", style);
                List<CitationModel> dicStyle = HttpUtil.Post<List<CitationModel>>(Constant.API_引文格式化_指定样式, dicParam);
                if (dicStyle == null) return false;
                
                modelList.ForEach(model =>
                {
                    CitationModel citation = dicStyle.Find(c => c.ID == model.ID && c.Style.Equals(style, StringComparison.InvariantCultureIgnoreCase));
                    if (citation == null) return;

                    var selection = Globals.ThisAddIn.Application.Selection;
                    var selectionRange = selection.Range;

                    int selectionStart = selection.Start;
                    int selectionEnd = selection.End;

                    List<IdEndnote> idEndnoteList = GetIdEndnoteList(model.ID);
                    // 添加交叉引用
                    if (idEndnoteList.Count > 0)
                    {
                        selection.InsertCrossReference(WdReferenceType.wdRefTypeEndnote, WdReferenceKind.wdEndnoteNumber, idEndnoteList[0].Endnote.Index, true);

                        int nowSelectionStart = selection.Start;
                        int nowSelectionEnd = selection.End;

                        if (nowSelectionStart != selectionStart && nowSelectionEnd != selectionEnd)
                        {
                            var crossReferenceRange = doc.Range(selectionEnd, nowSelectionStart);
                            crossReferenceRange.Font.Superscript = 1;
                        }
                    }
                    // 不存在该尾注，添加新尾注
                    else
                    {
                        var endNote = endNotes.Add(selectionRange, Type.Missing, citation.Citation.TrimEnd('\r','\n'));

                        string bookmarkName = ReferenceModel.GetBookmarkNameFromID(model.ID);
                        doc.Bookmarks.Add(bookmarkName, selectionRange);
                        doc.Bookmarks.Add(bookmarkName, endNote.Reference);
                    }
                    
                    var referenceItem = GetRefPanelModel().RefPanel.ReferenceList.Find(r => r.ReferenceModel.ID == model.ID);
                    if (referenceItem != null) referenceItem.SetUsed(true);
                });

                GetRefPanelModel().RefPanel.UpdateItemPosition();

                return true;
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }

            return false;
        }

        private List<IdEndnote> GetIdEndnoteList(string referenceId = null) 
        {
            List<IdEndnote> idEndnoteList = new List<IdEndnote>();

            try
            {

                var doc = Globals.ThisAddIn.Application.ActiveDocument;
                foreach (Endnote endNote in doc.Endnotes)
                {
                    foreach (Bookmark bookmark in endNote.Reference.Bookmarks)
                    {
                        string id = ReferenceModel.GetIDFromBookmarkName(bookmark.Name);
                        if (!string.IsNullOrEmpty(id) && idEndnoteList.Find(idEndnote => idEndnote.ID == id) == null)
                        {
                            if (string.IsNullOrEmpty(referenceId))
                            {
                                idEndnoteList.Add(new IdEndnote { ID = id, Endnote = endNote });
                            }
                            else if (referenceId == id)
                            {
                                idEndnoteList.Add(new IdEndnote { ID = id, Endnote = endNote });
                                return idEndnoteList;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }

            return idEndnoteList;
        }

        private bool AddToPanel(List<ReferenceModel> modelList, bool addEndnote=false)
        {
            try
            {
                if (modelList == null || modelList.Count <= 0) return false;
                
                Dictionary<string, string> dicParam = new Dictionary<string, string>();
                dicParam.Add("id", string.Join(",", modelList.Select(m => m.ID).ToArray()));
                HttpUtil.Post<string>(Constant.API_添加到远程面板, dicParam);

                return DoAddToPanel(modelList, addEndnote);
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }

            return false;
        }

        private bool DoAddToPanel(List<ReferenceModel> modelList, bool addEndnote =false)
        {
            var refPanelModel = GetRefPanelModel();
            if (refPanelModel == null) return false;
            var idList = refPanelModel.RefPanel.ReferenceList.Select(r=>r.ReferenceModel.ID).ToList();
            var newIdList = modelList.Select(r => r.ID).ToList();
            string idListStr = string.Join(Environment.NewLine, idList.ToArray());
            string newIdListStr = string.Join(Environment.NewLine, newIdList.ToArray());
            modelList.ForEach(model => {
                if (refPanelModel.RefPanel.ReferenceList.Exists(r => r.ReferenceModel.ID == model.ID)) return;
                refPanelModel.RefPanel.AddReference(model);
            });
            
            if (addEndnote)
            {
                InsertCitation(modelList);
            }
            else
            {
                RefreshCitationPanelStatus();
            }
            
            return true;
        }

        /// <summary>
        /// 刷新引用面板是否被引用的状态
        /// </summary>
        private void RefreshCitationPanelStatus(Window window = null)
        {
            try
            {
                var refPanelModel = GetRefPanelModel(window);
                if (refPanelModel != null) refPanelModel.RefPanel.RefreshUseStatus(refPanelModel.Window.Document);
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        ///// <summary>
        ///// 刷新文档中引用标注与引文的状态
        ///// </summary>
        //private void RefreshCitationDocStatus()
        //{
        //    try
        //    {
        //        var refPanelModel = GetRefPanelModel();
        //        if (refPanelModel != null)
        //            refPanelModel.RefPanel.RefreshUseStatus(refPanelModel.Window.Document);

        //        if (citationStyle.SelectedItem == null)
        //        {
        //            WinApp.MsgBoxError("请设置要插入的格式");
        //            return;
        //        }

        //        string style = citationStyle.SelectedItem.Label;
        //        if (string.IsNullOrEmpty(style))
        //        {
        //            WinApp.MsgBoxError("样式不能为空");
        //            return;
        //        }
        //        var doc = Globals.ThisAddIn.Application.ActiveDocument;

        //        List<IdEndnote> idEndnoteList = new List<IdEndnote>();

        //        foreach (Endnote endNote in doc.Endnotes)
        //        {
        //            string text = endNote.Range.Text;
        //            if (text != null) text = text.Trim();

        //            if (!string.IsNullOrEmpty(text)) continue;

        //            foreach (Bookmark bookmark in endNote.Reference.Bookmarks)
        //            {
        //                string id = ReferenceModel.GetIDFromBookmarkName(bookmark.Name);
        //                if (!string.IsNullOrEmpty(id))
        //                {
        //                    idEndnoteList.Add(new IdEndnote { ID = id, Endnote = endNote });
        //                    continue;
        //                }
        //            }
        //        }

        //        string ids = string.Join(",", idEndnoteList.Select(i => i.ID).Distinct().ToArray());
        //        if (string.IsNullOrEmpty(ids)) return;

        //        Dictionary<string, string> dicParam = new Dictionary<string, string>();
        //        dicParam.Add("id", ids);
        //        dicParam.Add("style", style);
        //        List<CitationModel> dicStyle = HttpUtil.Post<List<CitationModel>>(Constant.API_引文格式化_指定样式, dicParam);
        //        if (dicStyle == null) return;

        //        idEndnoteList.ForEach(inote =>
        //        {
        //            CitationModel citation = dicStyle.Find(c => c.ID == inote.ID && c.Style.Equals(style, StringComparison.InvariantCultureIgnoreCase));
        //            if (citation == null) return;
        //            inote.Endnote.Range.Text = citation.Citation;
        //        });
        //    }
        //    catch (Exception ex)
        //    {
        //        LogHelper.Error(ex);
        //    }
        //}

        private class IdEndnote {
            public string ID { get; set; }
            public Endnote Endnote { get; set; }
        }

        private void ApplyCitationStyle()
        {
            try
            {
                if (citationStyle.SelectedItem == null) return;
                string style = citationStyle.SelectedItem.Label;

                // 格式变更，刷新当前word的引文内容
                List<IdEndnote> idEndnoteList = GetIdEndnoteList();
                
                string ids = string.Join(",", idEndnoteList.Select(i => i.ID).Distinct().ToArray());
                if (string.IsNullOrEmpty(ids)) return;

                Dictionary<string, string> dicParam = new Dictionary<string, string>();
                dicParam.Add("id", ids);
                dicParam.Add("style", style);
                List<CitationModel> dicStyle = HttpUtil.Post<List<CitationModel>>(Constant.API_引文格式化_指定样式, dicParam);
                if (dicStyle == null) return;
                
                idEndnoteList.ForEach(inote =>
                {
                    CitationModel citation = dicStyle.Find(c => c.ID == inote.ID && c.Style.Equals(style, StringComparison.InvariantCultureIgnoreCase));
                    if (citation == null) return;
                    inote.Endnote.Range.Text = citation.Citation;
                });
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        private void PanelSetCitationStyle() 
        {
            try
            {
                if (_setCitationStyle.ShowDialog() != DialogResult.OK || string.IsNullOrEmpty(_setCitationStyle.SelectedCitationStyle))
                    return;

                string style = _setCitationStyle.SelectedCitationStyle;
                // 设置下拉框
                foreach (var item in citationStyle.Items)
                {
                    if (item.Label == style)
                    {
                        citationStyle.SelectedItem = item;
                        ApplyCitationStyle();
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
                WinApp.MsgBoxError(ex.Message);
            }
        }

        private void PanelSearchCitation() 
        {
            try
            {
                if (!CheckLogin()) return;

                _insertCitation.EnableInsert = false;
                _insertCitation.ShowDialog();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }

        private void PanelRereshCitationStatus()
        {
            try
            {
                if (!CheckLogin()) return;
                
                ApplyCitationStyle();
                RefreshCitationPanelStatus();
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        private void QueryUserReferencePanelData()
        {
            var refPanelModel = GetRefPanelModel();
            if (refPanelModel != null) refPanelModel.RefPanel.ClearRefrence();
            List<ReferenceModel> referenceModelList = HttpUtil.Post<List<ReferenceModel>>(Constant.API_面板引文, null);
            if (referenceModelList != null)
            {
                DoAddToPanel(referenceModelList);
                RefreshCitationPanelStatus();
            }
        }
        #endregion

        private void btnHelp_Click(object sender, RibbonControlEventArgs e)
        {
            try
            {
                System.Diagnostics.Process.Start(string.Format(Constant.HOST + Constant.HELP, Constant.VERSION));
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
    }
}
